#ifndef SRS_KERNEL_CONTAINER_HPP
#define SRS_KERNEL_CONTAINER_HPP

#include <list>

class RtuMutex
{
public:
	RtuMutex(SRWLOCK *mutex)
    {
        _mutex = mutex;
		AcquireSRWLockExclusive(_mutex);
    }

    ~RtuMutex()
    {
		AcquireSRWLockExclusive(_mutex);
    }

private:
	SRWLOCK* _mutex;
};

/**
 * @brief The SrsRtuPacketArray class
 *
 */
template<class T>
class SrsRtuPacketArray
{
public:
    T** pkts;		///< the pointer array to save the packet
    int size;		///< current number of packets in the pkts from index 0
    int max;		///< the pkts size
public:
    SrsRtuPacketArray(int max_size)
    {
        pkts = new T*[max_size];
        bzero(pkts,sizeof(void*) * max_size);

        max = max_size;
        size = 0;
    }

    virtual ~SrsRtuPacketArray()
    {
        srs_freepa(pkts);
    }

public:
    /**
     * @brief grow
     * 	double the max size.
     */
    void grow()
    {
        max *= 2;
        T** new_pkts = new T*[max];
        bzero(new_pkts,sizeof(void*) * max);

        memcpy(new_pkts,pkts,sizeof(void*) * size);
        srs_freepa(pkts);

        pkts = new_pkts;
    }

public:
    /**
     * @brief copy
     * 	return the copy of the current array.
     *  NOTING: if you want to use this function, place reload the 'operator =' of class T
     */
    SrsRtuPacketArray* copy()
    {
        SrsRtuPacketArray* _copy = new SrsRtuPacketArray(max);
        _copy->size = size;

        for(int i = 0; i < size; i++) {
            srs_assert(pkts[i]);
            _copy->pkts[i] = new T;
            *(_copy->pkts[i]) = *(pkts[i]);
        }

        return _copy;
    }

public:
    /**
     * @brief free
     * 	free all the packets in the pkts (invoke the destructor).
     */
    void free()
    {
        for(int i = 0; i < size; i++) {
            srs_freep(pkts[i]);
        }
        size = 0;
    }

public:
    /**
     * @brief clear
     *  set all pointer saved in pkts to NULL.
     */
    void clear()
    {
        bzero(pkts, sizeof(void*) * size);
        size = 0;
    }

public:
    /**
     * @brief left_size
     */
    int left_size()
    {
        return max - size;
    }

public:
    /**
     * @brief empty
     * 	is there any room in pkts.
     */
    bool empty()
    {
        return size >= max;
    }
};


/**
 * a thread safety wrapper for standard list
 */
template <class T>
class SrsRtuList
{
public:
    int _size;
    std::list<T*> queue;
	SRWLOCK _mutex;

public:
    SrsRtuList()
    {
		InitializeSRWLock(&_mutex);
        _size = 0;
    }

    virtual ~SrsRtuList()
    {
        free();

        //pthread_mutex_destroy(&_mutex);
    }

public:
    void free()
    {
        RtuMutex lock(&_mutex);

        _size = 0;

        typename std::list<T*>::iterator it = queue.begin();
        for(; it != queue.end(); ++it) {
            T* unit = *it;
            srs_freep(unit);
        }

        queue.clear();
    }

    int size()
    {
        return _size;
    }

    bool empty()
    {
        return _size == 0;
    }

    void push_back(T* unit)
    {
        srs_assert(unit);

        RtuMutex lock(&_mutex);
        queue.push_back(unit);

        _size += 1;
    }

    void push_back(T* array[],int size)
    {
        srs_assert(array);

        RtuMutex lock(&_mutex);

        for(int i = 0; i < size; i++) {
            queue.push_back(array[i]);
        }

        _size += size;
    }

    T* pop_front()
    {
        RtuMutex lock(&_mutex);

        if( _size == 0 ) {
            return NULL;
        }

        T* unit = queue.front();
        queue.pop_front();

        _size--;
        return unit;
    }
};

class RtuDataUnit
{
public:
    RtuDataUnit() {}
    virtual ~RtuDataUnit() {}
public:
    virtual int get_size() = 0;
};

/**
 * @brief The SrsRtuDataList class
 *  To calculate the input and output unit numbers&volume,
 * the data unit should inherit the RtuDataUnit::get_size()
 */
class SrsRtuDataList: public SrsRtuList<RtuDataUnit>
{
public:
    // number
    INT64 _push_count;
    INT64 _pop_count;

    // volume
    INT64 _push_size;
    INT64 _pop_size;
public:
    SrsRtuDataList()
    {
		InitializeSRWLock(&_mutex);
        _size = 0;

        _push_count = 0;
        _pop_count = 0;

        _push_size = 0;
        _pop_size = 0;
    }

    virtual ~SrsRtuDataList()
    {
        free();
        //pthread_mutex_destroy(&_mutex);
    }
public:
    void push_back(RtuDataUnit* unit)
    {
        srs_assert(unit);

        RtuMutex lock(&_mutex);
        queue.push_back(unit);

        _size += 1;
        _push_count++;
        _push_size +=  unit->get_size();
    }

    void push_back(RtuDataUnit* array[],int size)
    {
        srs_assert(array);

        RtuMutex lock(&_mutex);

        for(int i = 0; i < size; i++) {
            queue.push_back(array[i]);
            _push_size += array[i]->get_size();
        }

        _size += size;
        _push_count += size;
    }

    RtuDataUnit* pop_front()
    {
        RtuMutex lock(&_mutex);

        if( _size == 0 ) {
            return NULL;
        }

        RtuDataUnit* unit = queue.front();
        queue.pop_front();

        _size--;
        _pop_count++;
        _pop_size += unit->get_size();

        return unit;
    }

    INT64 push_count()
    {
        return _push_count;
    }

    INT64 pop_count()
    {
        return _pop_count;
    }

    INT64 push_size()
    {
        return _push_size;
    }

    INT64 pop_size()
    {
        return _pop_size;
    }
};



#endif // SRS_KERNEL_CONTAINER_HPP
